package com.mlethe.library.widget.progress;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.LinearInterpolator;

import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * 自定义图片进度
 *
 * @author Mlethe
 */
public class CustomProgressView extends View {

    @IntDef({HORIZONTAL, VERTICAL})
    @Retention(RetentionPolicy.SOURCE)
    public @interface Orientation {
    }

    public static final int HORIZONTAL = 1000;
    public static final int VERTICAL = 1001;

    private int width, height;

    private int normalId;
    private int progressId;
    private Bitmap normalImg;
    private Bitmap progressImg;
    private Matrix matrix;

    private Rect normalRect, progressRect, normalDestRect, progressDestRect;

    /**
     * 进度方向（竖直、水平）
     */
    @Orientation
    private int orientation = HORIZONTAL;
    private float maxProgress = 1;
    private float progress = 0;

    private boolean useAnim = false;
    /**
     * 一个周期波浪的长度
     */
    private int mWaveLength;

    /**
     * 波浪的路径
     */
    private Path mWavePath;

    /**
     * 平移偏移量
     */
    private int mOffset;

    /**
     * 一个屏幕内显示几个周期
     */
    private int mWaveCount;

    /**
     * 振幅
     */
    private int mWaveAmplitude;
    private ValueAnimator valueAnimator;

    private Paint mPaint, mPathPaint;

    public CustomProgressView(Context context) {
        this(context, null);
    }

    public CustomProgressView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CustomProgressView);
        normalId = array.getResourceId(R.styleable.CustomProgressView_ProgressBackground, 0);
        progressId = array.getResourceId(R.styleable.CustomProgressView_ProgressResource, 0);
        maxProgress = array.getFloat(R.styleable.CustomProgressView_MaxProgress, maxProgress);
        progress = array.getFloat(R.styleable.CustomProgressView_Progress, progress);
        orientation = array.getInt(R.styleable.CustomProgressView_Orientation, orientation);
        array.recycle();
        normalRect = new Rect();
        normalDestRect = new Rect();
        progressRect = new Rect();
        progressDestRect = new Rect();
        mWavePath = new Path();
        mWaveAmplitude = dp2px(5);
        mWaveLength = dp2px(100);
        mPathPaint = new Paint();
        mPathPaint.setAntiAlias(true);
        mPathPaint.setColor(Color.WHITE);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        createNormalBitmap();
        createProgressBitmap();
        if (useAnim) {
            startAnimation();
        }
    }

    /**
     * 创建进度背景
     */
    private void createNormalBitmap() {
        if (normalImg == null) {
            normalImg = createBitmap(matrix, normalId, width, height);
        }
    }

    /**
     * 创建进度
     */
    private void createProgressBitmap() {
        if (progressImg == null) {
            progressImg = createBitmap(matrix, progressId, width, height);
        }
    }

    /**
     * 创建绘制的图像
     *
     * @param matrix
     * @param resId
     * @param width
     * @param height
     * @return
     */
    private Bitmap createBitmap(Matrix matrix, int resId, int width, int height) {
        if (matrix != null) {
            if (resId != 0) {
                Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resId);
                int bitmapWidth = bitmap.getWidth();
                int bitmapHeight = bitmap.getHeight();
                matrix.reset();
                // 获取缩放比例
                float scaleWidth = (float) width / bitmapWidth;
                float scaleHeight = (float) height / bitmapHeight;
                matrix.postScale(scaleWidth, scaleHeight);
                // 根据缩放比例获取新的位图
                Bitmap createdBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmapWidth, bitmapHeight, matrix, true);
                bitmap.recycle();
                bitmap = null;
                return createdBitmap;
            }
        }
        return null;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        width = w;
        height = h;
        if (matrix == null) {
            matrix = new Matrix();
            createNormalBitmap();
            createProgressBitmap();
        }
        /**
         * 加上1.5是为了保证至少有两个波形（屏幕外边一个完整的波形，屏幕里边一个完整的波形）
         */
        mWaveCount = (int) Math.round(width / mWaveLength + 1.5);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (orientation == HORIZONTAL) {
            drawHorizontalBitmap(canvas);
        } else {
            drawVerticalBitmap(canvas);
        }
    }

    /**
     * 水平绘制
     *
     * @param canvas
     */
    private void drawHorizontalBitmap(Canvas canvas) {
        float ratio = progress / maxProgress;
        if (progressImg != null) {
            int width = progressImg.getWidth();
            int height = progressImg.getHeight();
            int right = (int) (width * ratio);
            progressRect.set(0, 0, right, height);
            progressDestRect.set(0, 0, right, height);
            canvas.drawBitmap(progressImg, progressRect, progressDestRect, null);
        }
        if (normalImg != null) {
            int width = normalImg.getWidth();
            int height = normalImg.getHeight();
            int left = (int) (width * ratio);
            normalRect.set(left, 0, width, height);
            normalDestRect.set(left, 0, width, height);
            canvas.drawBitmap(normalImg, normalRect, normalDestRect, null);
        }
    }

    /**
     * 竖直绘制
     *
     * @param canvas
     */
    private void drawVerticalBitmap(Canvas canvas) {
        float ratio = progress / maxProgress;
        if (useAnim && ratio < 1) {
            if (normalImg != null) {
                int width = normalImg.getWidth();
                int height = normalImg.getHeight();
                int bottom = (int) (height * (1 - ratio));
                mWavePath.reset();
                mWavePath.moveTo(-mWaveLength + mOffset, mWaveAmplitude + bottom);
                for (int i = 0; i < mWaveCount; i++) {
                    //第一个控制点的坐标为(-mWaveLength * 3 / 4,-mWaveAmplitude)
                    mWavePath.quadTo(-mWaveLength * 3 / 4 + mOffset + i * mWaveLength,
                            -mWaveAmplitude + bottom,
                            -mWaveLength / 2 + mOffset + i * mWaveLength,
                            mWaveAmplitude + bottom);

                    //第二个控制点的坐标为(-mWaveLength / 4,3 * mWaveAmplitude)
                    mWavePath.quadTo(-mWaveLength / 4 + mOffset + i * mWaveLength,
                            3 * mWaveAmplitude + bottom,
                            mOffset + i * mWaveLength,
                            mWaveAmplitude + bottom);
                }
                mWavePath.lineTo(width, 0);
                mWavePath.lineTo(0, 0);
                mWavePath.close();
                Bitmap srcBitmap = createBitmap(mWavePath, normalImg.getWidth(), normalImg.getHeight());
                Bitmap xfermodeBitmap = createXfermodeBitmap(normalImg, srcBitmap, normalImg.getWidth(), normalImg.getHeight());
                canvas.drawBitmap(xfermodeBitmap, 0, 0, null);
                xfermodeBitmap.recycle();
            }
            if (progressImg != null) {
                int height = progressImg.getHeight();
                int width = progressImg.getWidth();
                int top = (int) (height * (1 - ratio));
                mWavePath.reset();
                mWavePath.moveTo(-mWaveLength + mOffset, mWaveAmplitude + top);
                for (int i = 0; i < mWaveCount; i++) {
                    //第一个控制点的坐标为(-mWaveLength * 3 / 4,-mWaveAmplitude)
                    mWavePath.quadTo(-mWaveLength * 3 / 4 + mOffset + i * mWaveLength,
                            -mWaveAmplitude + top,
                            -mWaveLength / 2 + mOffset + i * mWaveLength,
                            mWaveAmplitude + top);

                    //第二个控制点的坐标为(-mWaveLength / 4,3 * mWaveAmplitude)
                    mWavePath.quadTo(-mWaveLength / 4 + mOffset + i * mWaveLength,
                            3 * mWaveAmplitude + top,
                            mOffset + i * mWaveLength,
                            mWaveAmplitude + top);
                }
                mWavePath.lineTo(width, height);
                mWavePath.lineTo(0, height);
                mWavePath.close();
                Bitmap srcBitmap = createBitmap(mWavePath, progressImg.getWidth(), progressImg.getHeight());
                Bitmap xfermodeBitmap = createXfermodeBitmap(progressImg, srcBitmap, progressImg.getWidth(), progressImg.getHeight());
                canvas.drawBitmap(xfermodeBitmap, 0, 0, null);
                xfermodeBitmap.recycle();
            }
        } else {
            if (normalImg != null) {
                int width = normalImg.getWidth();
                int height = normalImg.getHeight();
                int bottom = (int) (height * (1 - ratio));
                normalRect.set(0, 0, width, bottom);
                normalDestRect.set(0, 0, width, bottom);
                canvas.drawBitmap(normalImg, normalRect, normalDestRect, null);
            }
            if (progressImg != null) {
                int height = progressImg.getHeight();
                int width = progressImg.getWidth();
                int top = (int) (height * (1 - ratio));
                progressRect.set(0, top, width, height);
                progressDestRect.set(0, top, width, height);
                canvas.drawBitmap(progressImg, progressRect, progressDestRect, null);
            }
        }
    }

    /**
     * 创建bitmap
     *
     * @param path
     * @param width
     * @param height
     * @return
     */
    private Bitmap createBitmap(Path path, int width, int height) {
        Bitmap bm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bm);
        c.drawPath(path, mPathPaint);
        return bm;
    }

    /**
     * 创建XfermodeBitmap
     *
     * @param dstBitmap
     * @param srcBitmap
     * @return
     */
    private Bitmap createXfermodeBitmap(Bitmap dstBitmap, Bitmap srcBitmap, int width, int height) {
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        // 两个图片大小一致，且重叠？
        canvas.drawBitmap(dstBitmap, 0, 0, null);
        canvas.drawBitmap(srcBitmap, 0, 0, mPaint);
        srcBitmap.recycle();
        return bitmap;
    }

    /**
     * 开始动画
     */
    public void startAnimation() {
        useAnim = true;
        if (orientation == VERTICAL) {
            // 竖直方向（波形动画）
            valueAnimator = ValueAnimator.ofInt(0, mWaveLength);
            valueAnimator.setDuration(2000);
            valueAnimator.setStartDelay(300);
            valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
            valueAnimator.setInterpolator(new LinearInterpolator());
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mOffset = (int) animation.getAnimatedValue();
                    invalidate();
                }
            });
            valueAnimator.start();
        } else {
            // 水平方向
        }
    }

    /**
     * 暂停动画
     */
    public void pauseAnimation() {
        if (valueAnimator != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                valueAnimator.pause();
            }
        }
    }

    /**
     * 恢复动画
     */
    public void resumeAnimation() {
        if (valueAnimator != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                valueAnimator.resume();
            }
        }
    }

    /**
     * 停止动画
     */
    public void stopAnimation() {
        if (valueAnimator != null) {
            valueAnimator.cancel();
            valueAnimator = null;
        }
    }

    /**
     * dp 转 px
     *
     * @param dp
     */
    protected int dp2px(int dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
    }

    @Override
    protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        if (visibility == VISIBLE) {
            resumeAnimation();
        } else {
            pauseAnimation();
        }
    }

    @Override
    protected void onWindowVisibilityChanged(int visibility) {
        super.onWindowVisibilityChanged(visibility);
        if (visibility == VISIBLE) {
            resumeAnimation();
        } else {
            pauseAnimation();
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (matrix != null) {
            matrix.reset();
        }
        if (normalImg != null) {
            normalImg.recycle();
            normalImg = null;
        }
        if (progressImg != null) {
            progressImg.recycle();
            progressImg = null;
        }
        if (normalRect != null) {
            normalRect.setEmpty();
        }
        if (normalDestRect != null) {
            normalDestRect.setEmpty();
        }
        if (progressRect != null) {
            progressRect.setEmpty();
        }
        if (progressDestRect != null) {
            progressDestRect.setEmpty();
        }
        stopAnimation();
    }

    /**
     * 设置方向
     *
     * @param orientation
     * @return
     */
    public CustomProgressView setOrientation(@Orientation int orientation) {
        if (this.orientation == orientation) {
            return this;
        }
        this.orientation = orientation;
        postInvalidate();
        return this;
    }

    /**
     * 设置进度背景图片
     *
     * @param backgroundId
     */
    public CustomProgressView setProgressBackground(int backgroundId) {
        if (this.normalId == backgroundId) {
            return this;
        }
        this.normalId = backgroundId;
        if (normalImg != null) {
            normalImg.recycle();
            normalImg = null;
        }
        createNormalBitmap();
        postInvalidate();
        return this;
    }

    /**
     * 设置进度图片
     *
     * @param resourceId
     */
    public CustomProgressView setProgressResource(int resourceId) {
        if (this.progressId == resourceId) {
            return this;
        }
        this.progressId = resourceId;
        if (progressImg != null) {
            progressImg.recycle();
            progressImg = null;
        }
        createProgressBitmap();
        postInvalidate();
        return this;
    }

    /**
     * 设置最大进度
     *
     * @param maxProgress
     * @return
     */
    public CustomProgressView setMaxProgress(float maxProgress) {
        if (this.maxProgress == maxProgress) {
            return this;
        }
        this.maxProgress = maxProgress;
        postInvalidate();
        return this;
    }

    /**
     * 设置进度
     *
     * @param progress 进度
     * @return
     */
    public CustomProgressView setProgress(float progress) {
        if (this.progress == progress) {
            return this;
        }
        if (progress > maxProgress) {
            this.progress = maxProgress;
        } else if (progress < 0) {
            this.progress = 0;
        } else {
            this.progress = progress;
        }
        postInvalidate();
        return this;
    }

    /**
     * 一个周期波浪的长度
     *
     * @param waveLength
     * @return
     */
    public CustomProgressView setWaveLength(int waveLength) {
        if (this.mWaveLength == waveLength) {
            return this;
        }
        this.mWaveLength = waveLength;
        postInvalidate();
        return this;
    }

    /**
     * 一个屏幕内显示几个周期
     *
     * @param waveCount
     * @return
     */
    public CustomProgressView setWaveCount(int waveCount) {
        if (this.mWaveCount == waveCount) {
            return this;
        }
        this.mWaveCount = waveCount;
        postInvalidate();
        return this;
    }

    /**
     * 水波振幅
     *
     * @param waveAmplitude
     * @return
     */
    public CustomProgressView setWaveAmplitude(int waveAmplitude) {
        if (this.mWaveAmplitude == waveAmplitude) {
            return this;
        }
        this.mWaveAmplitude = waveAmplitude;
        postInvalidate();
        return this;
    }

}
